﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Dynamics.BusinessConnectorNet;
using System.Collections;

namespace PJ.Data
{
    /// <summary>
    /// Dynamics AX server implementation of <see cref="IItemProvider"> persistence interface. 
    /// </summary>
    /// <typeparam name="TIItemData">Item data interface type</typeparam>
    /// <typeparam name="TItemData">Item data concrete class type</typeparam>
    public abstract class ItemAXProvider<TIItemData> : EntityAXProvider<TIItemData>, IItemProvider<TIItemData>
        where TIItemData : class, IItemData
    {
        protected ItemAXProvider(IItemCache<TIItemData> cache)
            : base(cache)
        {

        }
        protected override void CopyFromContainer(IEnumerator enumerator, TIItemData data)
        {
            base.CopyFromContainer(enumerator, data);
            if (enumerator.MoveNext())
            {
                data.Name = ((string)enumerator.Current).Trim();
                if (enumerator.MoveNext())
                {
                    data.AliasName = ((string)enumerator.Current).Trim();
                    return;
                }
            }
            throw new ArgumentException("Container size error", "enumerator");
        }

        #region Interface implementation


        public virtual TIItemData GetByName(string name, GetDataMode mode)
        {
            if (name == null || name == "")
                throw new ArgumentNullException("name");
            TIItemData data = null;
            if (Cache != null && (mode & GetDataMode.UseCache) == GetDataMode.UseCache)
                data = Cache.FindByName(name);
            if (data == null)
            {
                using (AxaptaContainer container =
                    (AxaptaContainer)CallAXStaticMethod("FindByName", name))
                {
                    IEnumerator enumerator = container.GetEnumerator();
                    if (enumerator.MoveNext())
                    {
                        data = CreateNewItem(enumerator);
                        if (enumerator.MoveNext())
                            throw new Exception("Container size error");
                        if (Cache != null)
                            Cache.Add(data);
                    }
                }
            }
            if (data == null && (mode & GetDataMode.Find) != GetDataMode.Find)
                throw new DataNotFoundException("name", name);
            return data;

        }

        public virtual TIItemData GetByAlias(string aliasName, GetDataMode mode)
        {
            if (aliasName == null || aliasName == "")
                throw new ArgumentNullException("aliasName");
            TIItemData data = null;
            if (Cache != null && (mode & GetDataMode.UseCache) == GetDataMode.UseCache)
                data = Cache.FindByAlias(aliasName);
            if (data == null)
            {
                using (AxaptaContainer container =
                    (AxaptaContainer)CallAXStaticMethod("FindByAlias", aliasName))
                {
                    IEnumerator enumerator = container.GetEnumerator();
                    if (enumerator.MoveNext())
                    {
                        data = CreateNewItem(enumerator);
                        if (enumerator.MoveNext())
                            throw new ArgumentException("Container size error", "container");
                        if (Cache != null)
                            Cache.Add(data);
                    }
                }
            }
            if (data == null && (mode & GetDataMode.Find) != GetDataMode.Find)
                throw new DataNotFoundException("aliasName", aliasName);
            return data;
        }

        public virtual string[] Search(string searchText, GetDataMode mode)
        {
            if (searchText == null || searchText == "")
                throw new ArgumentNullException("searchText");
            string[] searchResult = null;
            if (Cache != null && (mode & GetDataMode.UseCache) == GetDataMode.UseCache)
                searchResult = Cache.Search(searchText);
            if (searchResult == null)
            {
                using (AxaptaContainer container = (AxaptaContainer)CallAXStaticMethod("Search", searchText))
                {
                    if (container.Count != 0)
                    {
                        List<string> list = new List<string>();
                        for (int i = 0; i < container.Count; i += 2)
                            list.Add(GetGlobalId((int)container.get_Item(i + 1), (Int64)container.get_Item(i + 2)));
                        if (Cache != null)
                            Cache.AddSearch(searchText, list.ToArray());
                        searchResult = list.ToArray();
                    }
                }

            }
            if (searchResult == null && (mode & GetDataMode.Find) != GetDataMode.Find)
                throw new DataNotFoundException("searchTxt", searchText);
            return searchResult;
        }

        #endregion

        #region Interface override

        IItemData IItemProvider.GetByName(string name, GetDataMode mode)
        {
            return GetByName(name, mode);
        }

        IItemData IItemProvider.GetByAlias(string aliasName, GetDataMode mode)
        {
            return GetByAlias(aliasName, mode);
        }


        new protected IItemCache<TIItemData> Cache
        {
            get { return base.Cache as IItemCache<TIItemData>; }
        }
        #endregion

    }
}
